// Copyright 2008 Steve Spiller. All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//    1. Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//    2. Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//       
// THIS SOFTWARE IS PROVIDED BY THE KAOS PROJECT ``AS IS'' AND ANY EXPRESS 
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 
// NO EVENT SHALL THE PROJECT OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#pragma once

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include "SystemTypes.h"

class ConfigException: public std::exception
{
public:
    ConfigException(const char * msg) : m_msg(msg) { }
    
    virtual const char* what() const throw()
    {
        return m_msg;
    }
    
private:
    const char * m_msg;
};

class CDriverConfig
{
public:
    enum DriverConfigValue
    {
        // These values represent strings
        __MUD_NAME__,
        __ADDR_SERVER_IP__,
        __MUD_LIB_DIR__,
        __BIN_DIR__,
        __LOG_DIR__,
        __INCLUDE_DIRS__,
        __SAVE_BINARIES_DIR__,
        __MASTER_FILE__,
        __SIMUL_EFUN_FILE__,
        __SWAP_FILE__,
        __DEBUG_LOG_FILE__,
        __DEFAULT_ERROR_MESSAGE__,
        __DEFAULT_FAIL_MESSAGE__,
        __GLOBAL_INCLUDE_FILE__,
        __MUD_IP__,

        // These values represent integers 
        __MUD_PORT__,
        __ADDR_SERVER_PORT__,
        __TIME_TO_CLEAN_UP__,
        __TIME_TO_RESET__,
        __TIME_TO_SWAP__,
        __INHERIT_CHAIN_SIZE__,
        __MAX_EVAL_COST__,
        __MAX_ARRAY_SIZE__,
        __MAX_BUFFER_SIZE__,
        __MAX_MAPPING_SIZE__,
        __MAX_STRING_LENGTH__,
        __MAX_BITFIELD_BITS__,
        __MAX_BYTE_TRANSFER__,
        __MAX_READ_FILE_SIZE__,
        __RESERVED_MEM_SIZE__,
        __SHARED_STRING_HASH_TABLE_SIZE__,
        __OBJECT_HASH_TABLE_SIZE__,

        // These values come from options.h
        __MAX_LOCAL_VARIABLES__,
        __MAX_CALL_DEPTH__,
        __LIVING_HASH_TABLE_SIZE__,
        __COMPILER_STACK_SIZE__,
        __EVALUATOR_STACK_SIZE__
    };

    struct configInfo
    {
        UINT        index;
        INT         required;
        std::string label;
        std::string name;
    };

    static const struct configInfo configValueTable[];
    static const CHAR runtimeFileName[];

    static const INT firstIntValue      = __MUD_PORT__;
    static const INT countIntValues     = 22;
    static const INT countStringValues  = 15;

public:
    CDriverConfig();
    ~CDriverConfig();

    static CDriverConfig* GetConfig(void);

    void Load(std::string fileName);
    void Reload();
    void WriteRuntimeConfig(std::string path);

    INT GetConfigInt(DriverConfigValue which);
    std::string GetConfigString(DriverConfigValue which);

private:
    inline std::string TrimString(const std::string& src, const std::string& c = " \r\n")
    {   
        size_t p2 = src.find_last_not_of(c);
        if (p2 == std::string::npos) return std::string();
        size_t p1 = src.find_first_not_of(c);
        if (p1 == std::string::npos) p1 = 0;
        return src.substr(p1, (p2 - p1) + 1);
    }

private:
    std::string                 m_fileName;
    std::vector<INT>            m_intValues;
    std::vector<std::string>    m_stringValues;
    static CDriverConfig*       m_pInstance;
};
